package showtime.framework.net.rpc
{
	import flash.events.AsyncErrorEvent;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.NetStatusEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.NetConnection;
	import flash.net.ObjectEncoding;
	import flash.utils.Dictionary;
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	
	/** 
	 * @project showtime
	 * @author yinhao
	 * @date 2011-1-7 
	 * 
	 */
	
	dynamic public class BaseRpc extends Proxy implements IEventDispatcher
	{
		/**
		 * Gate way. 
		 */		
		private var endpoint:String = null;
		
		private var netConnection:NetConnection = null;
			
		private var dispatcher:EventDispatcher = null;
		
		private var operationMap:Dictionary = null;
		
		/**
		 * Destination of remote service. 
		 */		
		public var destination:String = null;
		
		/**
		 * Async waiting job.  
		 */		
		public var asyncWaitingFor:Function = null;  
		
		public function BaseRpc(endpoint:String, objectEncoding:uint = ObjectEncoding.DEFAULT) 
		{             
			operationMap = new Dictionary(true);
		
			this.endpoint = endpoint;
			
			dispatcher = new EventDispatcher(this);
			
			netConnection = new NetConnection();
			
			netConnection.client = this;
			
			netConnection.objectEncoding = objectEncoding;
			
			netConnection.addEventListener(NetStatusEvent.NET_STATUS, eventHandler);
			netConnection.addEventListener(IOErrorEvent.IO_ERROR, eventHandler);
			netConnection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, eventHandler);
			netConnection.addEventListener(AsyncErrorEvent.ASYNC_ERROR, eventHandler);
			netConnection.connect(endpoint);
		}
		
		public function setRemoteCredentials(userName:String, secret:String):void
		{
			netConnection.addHeader("Credentials", false, {userid:userName, password:secret});
			
		}
		
		public function getConnection():NetConnection
		{
			return netConnection;
		}
		
		public function toString():String
		{				
			return "[Service endpoint = " + endpoint + ", destination = " + destination + ", objectEncoding = " + netConnection.objectEncoding + "]";  
		}
		/**
		 * Event handler. 
		 * @param evt
		 * 
		 */		
		private function eventHandler(evt:Event):void
		{
			switch (evt.type)
			{
				case AsyncErrorEvent.ASYNC_ERROR:
				{
					break;
				}
				default:
				{
					dispatchEvent(evt);
				}
			}
		}
		private function getOperation(name:String):Operation
		{
			var operation:Operation = operationMap[name];
			
			if (operation == null)
			{
				operation = new Operation(this, name);
				operationMap[name] = operation;
			}
			
			return operation;
		}
		
		private function getLocalName(name:*):String
		{
			if (name is QName)
			{
				return QName(name).localName;
			}
			return String(name);
		}
		
		override flash_proxy  function getProperty(name:*):*
		{
			return getOperation(getLocalName(name));
		}
		
		override flash_proxy function callProperty( methodName:*, ...parametres:*):*
		{
			return getOperation(getLocalName(methodName)).send.apply(null,parametres);
		}
		
		public function dispatchEvent(evt:Event):Boolean
		{
			return dispatcher.dispatchEvent(evt);	
		}
		
		public function hasEventListener(type:String):Boolean
		{
			return dispatcher.hasEventListener(type);
		}
		
		public function willTrigger(type:String):Boolean
		{
			return dispatcher.willTrigger(type);
		}
		
		public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
		{
			dispatcher.removeEventListener(type, listener, useCapture);
		}
		
		public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
		{
			dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference); 
		}
		
		public function AppendToGatewayUrl(info:String):void
		{
			//trace(info);
		}
		
	}
}